package com.zzyl.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.zzyl.constant.CacheConstants;
import com.zzyl.entity.AlertRule;
import com.zzyl.mapper.AlertRuleMapper;
import com.zzyl.mapper.NursingElderMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.service.AlertService;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.DeviceDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class AlertServiceImpl implements AlertService {

    @Autowired
    private AlertRuleMapper alertRuleMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private NursingElderMapper nursingElderMapper;

    @Autowired
    private UserMapper userMapper;
    @Override
    public void checkAlarm(List<DeviceDataVo> deviceDataList){
        // 检查某个设备的某个functionId的value是否异常
        for (DeviceDataVo data : deviceDataList) {
            String productKey = data.getProductKey();
            String iotId = data.getIotId();
            String functionId = data.getFunctionId();
            String dataValue = data.getDataValue();
            LocalDateTime alarmTime = data.getAlarmTime();
            // 获取对应当前数据的告警规则
            List<AlertRule> rules = alertRuleMapper.selectByProductIotIdFucntionId(productKey, iotId, functionId);
            if(CollectionUtils.isEmpty(rules)){
                continue;
            }
            // 计算是否出现告警
            for (AlertRule rule : rules) {
                // 判断时间，如果不在告警的时间段范围之内，就不处理
                String alertEffectivePeriod = rule.getAlertEffectivePeriod();
                if(StringUtils.isEmpty(alertEffectivePeriod)){
                    continue;
                }
                String[] arr = rule.getAlertEffectivePeriod().split("~");
                LocalTime startTime = LocalTime.parse(arr[0]);
                LocalTime endTime = LocalTime.parse(arr[1]);
                //上报时间
                LocalTime dataTime = LocalDateTimeUtil.of(alarmTime).toLocalTime();
                if(dataTime.isBefore(startTime) || dataTime.isAfter(endTime)){
                    continue;
                }
                // 找到一条报警规则规则
                String operator = rule.getOperator();
                Float ruleValue = rule.getValue();
                if(Objects.equals(operator, ">=")){
                    if(Float.parseFloat(dataValue) >= ruleValue){
                        // 触发告警
                        //log.info("data:{} 触发 告警：{}", JSONUtil.toJsonStr(data), JSONUtil.toJsonStr(rule) );
                        prepareAlert(data, rule);
                    }
                }else{
                    if(Float.parseFloat(dataValue) < ruleValue){
                        // 触发告警
                        //log.info("data:{} 触发 告警：{}", JSONUtil.toJsonStr(data), JSONUtil.toJsonStr(rule) );
                        prepareAlert(data, rule);
                    }
                }
            }
        }
    }

    private void prepareAlert(DeviceDataVo data, AlertRule rule){
        // 持续周期
        Integer duration = rule.getDuration();
        // 读取redis中的旧的持续周期值
        String durationKey = CacheConstants.IOT_DEVICE_ALERT_DURATION + data.getIotId() +":" + data.getFunctionId() +":" + rule.getId();
        // 把旧的持续周期+1
        Long increment = redisTemplate.opsForValue().increment(durationKey);
        // 设置过期时间，不要超过2个持续周期
        redisTemplate.expire(durationKey, 8, TimeUnit.SECONDS);
        // 到达持续周期
        if(increment >= duration){
            // 获取静默周期的key
            String silentKey = CacheConstants.IOT_DEVICE_ALERT_SILENT + data.getIotId() +":" + data.getFunctionId() +":" + rule.getId();
            Boolean exists = redisTemplate.hasKey(silentKey);
            if(exists){
                // 处于静默周期
                log.info("处于静默周期");
            }else{
                // 发告警
                // 设置静默周期
                Integer alertSilentPeriod = rule.getAlertSilentPeriod();
                redisTemplate.opsForValue().set(silentKey, "silent", alertSilentPeriod, TimeUnit.MINUTES);
                // 清零持续周期
                redisTemplate.delete(durationKey);
                // 保存告警数据，发短信，打电话。。。。。。
                log.info("触发告警");
                triggerAlert(data, rule);
            }
        }else{
            log.info("次数：{} 没有达持续周期：{}", increment, duration);
        }
    }

    private void triggerAlert(DeviceDataVo data, AlertRule rule){
        // 保存告警数据
        // 如果是老人的数据异常，发给护理人员和系统管理员
        Set<Long> userIds = new HashSet<>();
        if(Objects.equals(rule.getAlertDataType(), 0)){
            if(Objects.equals(data.getLocationType(), 0)){
                // 随身设备
                // device表binding_location = 老人的id
                // nursing_elder表中根据老人的id查询到护理人员的id
                List<Long> nursingIds = nursingElderMapper.selectNursingIdByPortableIotId(data.getIotId());
                if(!CollectionUtils.isEmpty(nursingIds)){
                    userIds.addAll(nursingIds);
                }
            }else{
                // 睡眠检测带，固定设备
                // device表中的binding_location=床的id
                // elder表有bed_id
                // nursing_elder表中根据老人的id查询到护理人员的id
                List<Long> nursingIds = nursingElderMapper.selectNursingIdByFixedIotId(data.getIotId());
                if(!CollectionUtils.isEmpty(nursingIds)){
                    userIds.addAll(nursingIds);
                }
            }
        }else{
            // 如果是硬件设备数据异常，发给设备管理员和系统管理员
            List<Long> uIds = userMapper.selectNursingIdByRoleName("维修工");
            if(!CollectionUtils.isEmpty(uIds)){
                userIds.addAll(uIds);
            }
        }
        List<Long> uIds = userMapper.selectNursingIdByRoleName("超级管理员");
        if(!CollectionUtils.isEmpty(uIds)){
            userIds.addAll(uIds);
        }
        log.info("接收人的id：{}", userIds);
        //TODO 发短信，打电话
    }
}